﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Threading;

namespace SampleCode.VirtualFS.ViewModel
{
    /// <summary>
    /// A thread-safe ObservableCollection. Supports only one working thread!
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class FsThreadSafeObservableCollection<T> : ObservableCollection<T>
    {
        private readonly Dispatcher _dispatcher;

        public FsThreadSafeObservableCollection(Dispatcher dispatcher)
        {
            _dispatcher = dispatcher;
        }

        private delegate void SetItemCallback(int index, T item);
        private delegate void RemoveItemCallback(int index);
        private delegate void ClearItemsCallback();
        private delegate void InsertItemCallback(int index, T item);
        private delegate void MoveItemCallback(int oldIndex, int newIndex);

        protected override void SetItem(int index, T item)
        {
            if (_dispatcher.CheckAccess())
                base.SetItem(index, item);
            else
                _dispatcher.BeginInvoke(DispatcherPriority.Send, new SetItemCallback(SetItem), index, new object[] { item });
        }

        protected override void RemoveItem(int index)
        {
            if (_dispatcher.CheckAccess())
                base.RemoveItem(index);
            else
                _dispatcher.BeginInvoke(DispatcherPriority.Send, new RemoveItemCallback(RemoveItem), index);
        }

        protected override void ClearItems()
        {
            if (_dispatcher.CheckAccess())
                base.ClearItems();
            else
                _dispatcher.BeginInvoke(DispatcherPriority.Send, new ClearItemsCallback(ClearItems));
        }

        protected override void InsertItem(int index, T item)
        {
            if (_dispatcher.CheckAccess())
                base.InsertItem(index, item);
            else
                _dispatcher.BeginInvoke(DispatcherPriority.Send, new InsertItemCallback(InsertItem), index, new object[] { item });
        }

        protected override void MoveItem(int oldIndex, int newIndex)
        {
            if (_dispatcher.CheckAccess())
                base.MoveItem(oldIndex, newIndex);
            else
                _dispatcher.BeginInvoke(DispatcherPriority.Send, new MoveItemCallback(MoveItem), oldIndex, new object[] { newIndex });
        }
    }
}
